﻿using RQX.Common.Core.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace RQX.Common.Core.Hardware.Net
{
    public class TcpSocketClient
    {
        #region 内部字段
        private readonly string _ip;
        private readonly int _port;
        private readonly IPEndPoint _iep;
        private readonly Socket _socket;
        private readonly int RecvBufferMaxLength = 5000000;
        #endregion

        #region 构造函数
        public TcpSocketClient(TcpSocketClient source) : this(source._ip, source._port)
        {
            HandleClosed = source.HandleClosed;
            HandleConnected = source.HandleConnected;
            HandleException = source.HandleException;
            HandleMsgReceived = source.HandleMsgReceived;
            HandleMsgSended = source.HandleMsgSended;
        }
        public TcpSocketClient(int port) : this("127.0.0.1", port) { }
        public TcpSocketClient(string ip, int port)
        {
            _ip = ip;
            _port = port;
            if (port == 0) return;
            _iep = new IPEndPoint(IPAddress.Parse(_ip), _port);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        #endregion

        #region 对外接口
        /// <summary>
        /// 获取连接信息
        /// </summary>
        /// <returns></returns>
        public string GetInfo() => $"{_ip}:{_port}";
        /// <summary>
        /// 判断是否连通
        /// </summary>
        /// <returns></returns>
        public bool IsConnected() => _socket?.Connected ?? false;
        /// <summary>
        /// 启动
        /// </summary>
        public void Start()
        {
            TryCatchMethod(() =>
            {
                _socket?.BeginConnect(_iep, asyncResult =>
                {
                    HandleConnected?.Invoke(this);
                    TryCatchMethod(() =>
                    {
                        Recv();
                    });
                }, null);
            });
        }

        public void Close()
        {
            _socket?.Close();
            HandleClosed?.Invoke(this);
        }


        public void Send(byte[] buffer)
        {
            TryCatchMethod(() =>
            {
                _socket?.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, asyncResult =>
                {
                    TryCatchMethod(() =>
                    {
                        _socket?.EndSend(asyncResult);
                        HandleMsgSended?.Invoke(this, buffer);
                    });
                }, null);
            });
        }
        public void SendHexString(string hexString)
        {
            var buffer = hexString.HexStringToByte();
            Send(buffer);
        }

        public void Recv()
        {
            byte[] container = new byte[RecvBufferMaxLength];
            TryCatchMethod(() =>
            {
                _socket?.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
                {
                    TryCatchMethod(() =>
                    {
                        var length = _socket.EndReceive(asyncResult);
                        byte[] buffer = new byte[length];
                        Array.Copy(container, buffer, length);
                        HandleMsgReceived?.Invoke(this, buffer);
                        container = null;
                        buffer = null;
                    });
                    Recv();
                }, null);
            });
        }
        #endregion

        #region 内部方法

        private void TryCatchMethod(Action action)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                Close();
                HandleException?.Invoke(this, ex);
            }
        }

        #endregion

        #region 事件处理
        /// <summary>
        /// 客户端连接上服务器后的事件
        /// </summary>
        public Action<TcpSocketClient> HandleConnected { get; set; }
        /// <summary>
        /// 接收到数据触发的事件
        /// </summary>
        public Action<TcpSocketClient, byte[]> HandleMsgReceived { get; set; }
        /// <summary>
        /// 发送数据后触发的事件
        /// </summary>
        public Action<TcpSocketClient, byte[]> HandleMsgSended { get; set; }
        /// <summary>
        /// 连接关闭事件
        /// </summary>
        public Action<TcpSocketClient> HandleClosed { get; set; }
        /// <summary>
        /// 异常处理事件
        /// </summary>
        public Action<TcpSocketClient, Exception> HandleException { get; set; }
        #endregion
    }
}
